#pragma once
#include "common.hpp"
#include <cstddef>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
using namespace std;
const int gdefaultid = -1;
const int gsize = 4096;
const string path = "./";
const int proid = 0x56;
const int gmode = 0666;
#define CREATE "creater"
#define USER "user"
class Shm {
private:
void CreateHelper(int flag) {
    printf("key:0x%x\n", _key);
    _shmid = shmget(_key, gsize, flag);
    if(_shmid < 0) {
        ERR_EXIT("shmget");
    }
    printf("shmid: %d\n", _shmid);
}
void Create() {
    CreateHelper(IPC_CREAT | IPC_EXCL | gmode);
}
void Attach() {
    _start_mem = shmat(_shmid, nullptr, 0);
    if((long long)_start_mem < 0) {
        ERR_EXIT("shmat");
    }
    printf("attch success\n");
}
void Detach() {
    int n = shmdt(_start_mem);
    if(n == 0) {
        cout << "detach success" << endl;
    }
}
void Get() {
    CreateHelper(IPC_CREAT);
}
void Destory() {
    Detach();
    if(_usertype == CREATE) {
        int n = shmctl(_shmid, IPC_RMID, nullptr);
    }else {
        ERR_EXIT("shmctl");
    }
}
public:
    Shm(const string& path, int projid, const string usertype) 
        :_shmid(gdefaultid),
        _size(gsize),
        _usertype(usertype),
        _start_mem(nullptr) {
            _key = ftok(path.c_str(), projid);
            if(_key < 0) {
                ERR_EXIT("ftok");
            }else {
                if(usertype == CREATE) {
                    Create();
                }else if(usertype == USER) {
                    Get();
                }else {
                }
                Attach();
            }
        }
        void* VirtualAddr() {
            printf("VirtualAddr: %p\n", _start_mem);
            return _start_mem;
        }
        int Size() {
            return _size;
        }
        void Attr() {
            struct shmid_ds ds;
            int n = shmctl(_shmid, IPC_STAT, &ds);
            printf("shm_segze: %zu\n", ds.shm_segsz);
            printf("key: 0x%x\n", ds.shm_perm.__key);
        }
        ~Shm() {
            cout << _usertype << endl;
            if(_usertype == CREATE) {
                Destory();
            }
        }
private:
    int _shmid;
    key_t _key;
    int _size;
    void* _start_mem;
    string _usertype;
};